package com.liziguo.lzgfp.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;

/**
 * @Author: Liziguo
 * @Date: 2021/12/24 20:41
 */
public class Main {

    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

    private static void instruction() {
        System.out.println("用法:java -jar xxx.jar [options] <key>");
        System.out.println("    key:由服务端生成的钥匙");
        System.out.println("options:");
        System.out.println("    -h <string>或--host=<string>");
        System.out.println("        服务器地址 默认:localhost");
        System.out.println("    -p <int>或--port=<int>");
        System.out.println("        服务器端口号 默认:9000");
        System.out.println("    -r <int>或--reconnect=<int>");
        System.out.println("        自动重连间隔 默认:30 单位秒");
        System.out.println("        输入-1或其他小于0的整数表示不自动重连");
        System.out.println("例:");
        System.out.println("    java -jar xxx.jar -h 192.168.1.2 -p 9100 -r 60 cMQsLp2ABn2iFOLmlrLq");
        System.out.println("https://gitee.com/li-ziguo/lzgfp");
    }

    public static void main(String[] args) {
        Options options = new Options(args);
        Globale.key = options.getString(0);
        if (Globale.key == null) {
            instruction();
            return;
        }
        Globale.SERVER_HOST = options.getString("-h", options.getString("--host", "localhost"));
        Globale.SERVER_PORT = options.getInt("-p", options.getInt("--port", 9000));
        Globale.AUTO_RECONNECT = options.getInt("-r", options.getInt("--reconnect", 30));
        Globale.setNextAutoReconnect(Globale.AUTO_RECONNECT);
        Globale.workerGroup = new NioEventLoopGroup();
        while (true) {
            final Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(Globale.workerGroup)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            final ChannelPipeline pipeline = socketChannel.pipeline();

                            /**
                             * lengthFieldLength:长度字段长度
                             * lengthIncludesLengthFieldLength：长度是否 包括长度字段长度
                             */
                            pipeline.addLast(new LengthFieldPrepender(3));
                            /**
                             * maxFrameLength：指定了每个包所能传递的最大数据包大小；
                             * lengthFieldOffset：指定了长度字段在字节码中的偏移量；
                             * lengthFieldLength：指定了长度字段所占用的字节长度；
                             * lengthAdjustment：对一些不仅包含有消息头和消息体的数据进行消息头的长度的调整，这样就可以只得到消息体的数据，这里的lengthAdjustment指定的就是消息头的长度；
                             * initialBytesToStrip：对于长度字段在消息头中间的情况，可以通过initialBytesToStrip忽略掉消息头以及长度字段占用的字节。
                             */
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(1024 * 1024, 0, 3, 0, 3));
                            pipeline.addLast(new StringEncoder(StandardCharsets.UTF_8));
                            pipeline.addLast(new StringDecoder(StandardCharsets.UTF_8));
                            pipeline.addLast(new InitHandler());
                        }
                    });
            ChannelFuture future = null;
            try {
                future = bootstrap.connect(Globale.SERVER_HOST, Globale.SERVER_PORT).sync();
                LOGGER.info("连接服务器成功{}:{}", Globale.SERVER_HOST, Globale.SERVER_PORT);
            } catch (Exception e) {
                LOGGER.info("连接服务器失败{}:{}", Globale.SERVER_HOST, Globale.SERVER_PORT);
            }

            if (future != null) {
                try {
                    future.channel().closeFuture().sync();
                } catch (Exception e) {
                    LOGGER.error("阻塞监听连接断开事件错误");
                }
            }
            final int time = Globale.getNextAutoReconnect();
            LOGGER.info("下次重连时间:{}秒后", time);
            if (time < 0) {
                LOGGER.info("重连时间小于0 结束程序");
                System.exit(0);
            }
            try {
                Thread.sleep(time * 1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
